Глава 7

Cookies в CFML

Cookies, так называемое "печенье" или, как еще иногда упоминают в литера-Туре, ячейки, позволяет хранить информацию на стороне клиента для последующего использования. Это может быть информация о клиенте, воспользовавшемся услугами сайта, о содержимом "покупательской корзины" в электронном магазине, о действиях, произведенных клиентом по отношению к расположенным на странице элементам формы.

Cookie является решением одной из проблем протокола HTTP (HyperText Transfer Protocol, протокол передачи гипертекста), которая заключается в непостоянстве соединения между клиентом и сервером. Включение cookie в HTTP-протокол способствовало частичному решению этой проблемы. То есть транзакция завершается после того, как браузер сделал запрос, а сервер выдал соответствующий ответ. Сразу после этого сервер "забывает" о пользователе и каждый следующий запрос того же пользователя считает переданным новым пользователем.

С помощью cookie можно эмулировать сессию по HTTP-протоколу. Принцип эмуляции сессии таков: на первом запросе выдается соответствующее значение cookie, а при каждом последующем запросе это значение читается из переменной окружения HTTP_COOKIE и соответствующим образом обрабатывается.

Cookie — это небольшая порция текстовой информации, которую сервер передает браузеру. Браузер будет хранить эту информацию и передавать ее серверу с каждым запросом как часть HTTP-заголовка. Некоторые значения cookie могут храниться только в течение одной сессии и удаляются после закрытия браузера. Другие, настроенные на определенный период времени, записываются в файл. Обычно этот файл называется cookies.txt и размещается в рабочем каталоге установленного на компьютере браузера.

Тег <CFCOOKIE>

Синтаксис:

<CFCOOKIE NAME="cookie_name" VALUE="text"

EXPIRES="period"

SECURE="Yes | No" PATH="urls" DOMAIN=".domain">

В табл. 7.1 представлено описание атрибутов тега <CFCOOKIE>.

Таблица 7.1. Описание атрибутов тега <CFCOOKIE>

Атрибут

Описание

NAME

 

VALUE

 

EXPIRES

 

SECURE

 

 

 

PATH

 

 

 

 


DOMAIN

Название переменной cookie. Обязательный атрибут Значение переменной cookie. Необязательный атрибут

Планирует жизненный цикл переменной cookie. Может быть определен как дата (например, 12/31/2001), число дней (например, 10), Now (сейчас) или Never (никогда). Использование значения Now удаляет cookie из клиентского браузера.

Является необязательным атрибутом и если не указывается, то cookie хранится в течение одного сеанса, до закрытия браузера

Указывает, что переменная должна быть передана по надежному каналу. Если этот атрибут имеет значение Yes, то информация cookie пересылается только через HTTPS (HTTP с использованием SSL, Secure Socket Level) в защищенном режиме. Иначе информация пересылается обычным способом. В случае использования защищенного режима и отсутствия на клиентском браузере SSL, cookie не будет создан. Необязательный атрибут

Этот атрибут определяет подмножество документов, для которых действительно значение cookie. Например, указание path="/my" приведет к тому, что значение cookie будет действительно для множества документов в каталогах /ту-арр1/, /mу-арр2/ и файлов в текущем каталоге с именами типа myfile1.html ' и myfile2.shtml. Для того чтобы cookie отсылались при каждом запросе к серверу, необходимо указать корневой каталог сервера, например, path="/". Для перечисления нескольких значений необходимо использовать разделитель ; (точку с запятой). Необязательный атрибут

Домен, для которого значение cookie действительно. Указанное значение должно всегда начинаться с точки, например, domain=" .Akhayan.com". Для перечисления нескольких значений необходимо использовать разделитель ; (точку с запятой). При использовании атрибута PATH необходимо указывать и атрибут DOMAIN

Cookies, написанные с использованием тега <CFCOOKIE>, не сохраняются в файле cookies.txt до конца сессии браузера. Пока браузер открыт, cookie хранится в памяти. Если атрибут EXPIRES не указан, cookie не записывается в файл cookies.txt и существует до завершения сессии браузера.

Если cookie принимает новое значение при имеющемся уже в браузере cookie с совпадающими атрибутами NAME, DOMAIN и PATH, то старое значение заменяется новым. В остальных случаях новые значения cookie добавляются к старым.

Использование атрибута EXPIRES не гарантирует сохранность cookie в течение заданного периода времени, поскольку клиент (браузер) может удалить запись из-за нехватки выделенного места или по каким-либо другим причинам.

Клиент (браузер) имеет следующие ограничения для cookies:

Если ограничение 300 или 20 превышается, то удаляется первая по времени запись. При превышении лимита объема в 4 Кбайт корректность значения cookie страдает — отсекается кусок записи (с начала этой записи), равный превышению объема.

Пример использования тега <CFCOOKIE>

Предположим, нам необходимо создать первую страницу сайта, предоставляющего информацию о круизах из Нью-Йорка, с предварительным запросом о национальном языке просмотра. При этом по согласованию с пользователем, в дальнейшем чтобы больше не озадачивать его подобными вопросами, в течение недели необходимо сразу загружать информацию на родном ему языке. Более того, немного усложним задачу: при загрузке выбранной пользователем страницы необходимо открывать окно с дополнительной информацией в течение всего времени до обусловленной даты. В качестве дополнительной информации может быть расписание сезонных рейсов, имеющее силу до определенного момента, или реклама с определенными сроками действия, или еще что-либо.

Решение данной задачи может быть следующим. Во-первых, нужно решить, сколько мы будем использовать cookies, а во-вторых, каким будет жизненный цикл для каждого cookie. Нам необходимо два cookies: первый будет определять выбранный язык, а второй — загрузку окна с дополнительной информацией. Для первого cookie, назовем его language, исходя из задачи, жизненный цикл укажем в семь дней. Для второго cookie, назовем его commercial, жизненный цикл зададим до конца 2001 года.

Следовательно, определение наших "пирожков" будет выглядеть следующим образом:

<CFCOOKIE NAME="language"

VALUE="#languagei" EXPIRES="7">

где #language# — значение переменной.

<CFCOOKIE NAME="commercial" VALUE="1" EXPIRES="12/31/2001">

Заметим, что "пирожок" commercial, будет "съеден" в ночь с 30 на 31 декабря 2001 года, а 31 числа от него уже ничего не останется, если только до этого момента он не будет "проглочен" клиентом браузера.

Для того чтобы прочитать значение cookie, в CFML используется конструкция cookie.Name, где Name — наименование cookie. Например:

<CFIF isDefined{"Cookie.language")>

<CFSET language=#Cookie.language#> </CFIF>

В этом коде проверяем наличие cookie с названием-language, и если такой существует, создаем переменную с подобным именем, определяя ей значение В соответствии с Cookie, language.

Далее продемонстрируем полный код страницы myjine.cfm, позволяющей решить поставленную выше задачу (листинг 7.1).

Листинг 7.1. Код страницы myjine.cfm

<HTML> <HEAD>

<МЕТА http-equiv="Content-Type" content="text/html;

charset=windows-1251">

<META name="Author" content="Ruben Akhayan">

<META http-equiv="Description" content="Cookies">

<TITLE>My-Line Cruises</TITLE> </HEAD>

<style type="text/css">

<!—-

.clRemLang { padding : Opx; font-weight : normal;

font-family : Verdana, Geneva, Arial, Helvetica, sans-serif;

font-size : llpx; color : #OOOOOO; }

. clPrompt {

padding : Opx; ront-welgnt ; bolder >

font-family : Verdana, Geneva, Arial/ Helvetica, sans-serif,

-font-size : llpx; color : #666699;

} #prompt {position: absolute; left: 10; top: 51; width: 406;

height: 10; margin: 0; z- index: 1; } -->

</style> <script>

var ns = (document. layers) ? true:

false var ie = (document .all) ? true: false

function layerWrite (id,nestref , text) { if (ns) {

var lyr = (nestref)? eval ( 'document . '+nestref+' .document . '+id+

'.document') : document . layers [id] .document lyr . open ( ) lyr .write (text) lyr

.close ()

} else if (ie) document .all [id] . innerHTML = text

}

function myLink(lang)

{

linecommand = "window.location.href = 'my_line.cfm?language="+

lang+"&remlang='#document.forml.RemLang.value+"'";

eval (linecoiranand) ;

}

function chbRemLang(value) {

if (value=='Yes') {

document.forml .RemLang.value = 'No';

} else {

document. forml.RemLang. value = 'Yes'

} }

</script>

<BODY>

<!--- Проверка наличия переменных --->

<CFIF isDefined("Cookie.language") OR isDefined("language")>

<script>document.bgColor="#666699";</script>

<CFIF isDefined("Cookie.language")>

<CFSET language=#Cookie.language#> </CFIF>

<CFIF isDefined("remlang")>

<CFIF remlang eq "Yes">

<!--- Устанавливаем Cookie-"language" --->

<CFCOOKIE NftME="language"

VALUE="#language#" EXPIRES="7"> </CFIF>

</CFIF>

<TABLE border='0' cellspacing='9' cellpadding='0'>

<TR><TD align="center" colspan="2">

<FONT size="5" color="White" face="Futura ><Blk BT">

MY-LINE CRUISES </FONTX/TD></TR>

<TRXTD bgcolor="White" height=l colspan="2"></td></tr>

<TR><TD><img src="fotoNY.gif" alt="" border="0"></td> <TR><TD>

<FONT size="2" color="White" face="Arial"?

<CFSWITCH EXPRE5SION=#language#> <CFCASE VALUE="rus"> <br>

<br> (My Line).<br>

</CFCASE>

<CFCASE VALUE="eng">

Discover why over 50 million people<br>

have chosen My Line as the best way to see New York.<br>

</CFCASE>

<CFCASE VALUE="ger">

Wie bereits mehr als 50 Millionnen Besucher vir Ihnen,

erleben und<br>

entdecken auch Sie New York bei einer Fahrt auf ainem der

My Line Schiffe.<br>

</CFCASE>

<CFCASE VALUE="spa">

Unase a raas de 50 millones de visitantes que han

palpado la<br>

emocion de descubrir a Nueva York a bordo de un barco

de My Line.<br>

</CFCASE> <CFDEFAULTCASE>

</CFDEFAULTCASE> </CFSWITCH> </FONT> </TD></TR> </table>

<CFIF isDefinedt"Cookie.commercial") is False>

<!--- Устанавливаем Cookie-"commercial" --->

<CFCOOKIE NAME="commercial" VALUE="1"

EXPIRES="12/31/2001"> <CFELSE>

<CFIF tCookie.commercial* eq 1> <script>

Variable = window.open("commercial.cfm", "windowname", "top-10, lQft=530, width=2bU, neight=49U" );

</script> </CFIF> </CFIF>

<CFELSE> <!--- Cookie.language не определен --->

<DIV id="prompt">

<TABLE border='0' cellspacing='0' cellpadding='0'>

<TR><TD width='400' class='clProrapt' align='right> New York's BEST<br>

Sightseeing and<br>Live Music<br>Cruises <TD></TR>

</TABLE> </DIV>

<FORM method='post' name='forml'>

<TABLE border='0' cellspacing='2' cellpadding='0'>

<TR><TD colspan="2" width="400" align="center" bgcolor="#666699">

<FONT size="5" color="White" face="Futura XBlk BT">

MY-LINE CRUISES </FONT></TD></TR>

<TR><TD colspan="2" bgcolor="#666699" height=lx/TD></TR>

<TR><TD colspan="2" valign="bottom" align="center"

height="342">

<IMG src="picl.gif" alt="" border="0" usemap="#MyMap"> </TD></TR>

<TR><TD class="clRemLang">

<input type="checkbox" name="RemLang" value="Yes" checked

onChange="javascript:chbRemLang(this.value);">

To remember the chosen language of viewing </TD>

<TD align="right">

<A HREF="javascript:myLink('rus');"

onMouseOver="javascript:layerWrite('prompt',null,

'-stable border=\'0\' cellspacing=\'0\'

cellpadding-\' 0\'xtrxtd width-\ ' 400\ '

class=\'clPrompt\' align=\ ' right\'Нью-Йорк ОТЛИЧНО<br>

Осмотр достопримечательностей и<br> Живая музыка<br>Круизы<td></tr></table>') ;

window.status='Russian'; return true"

onMouseOut="window.status=''; return true">

<img src="rus.gif" alt=""

border="0"></A>&nbsp;

<A HREF="javascript:myLink('eng');"

onMouseOver="javascript:layerWrite('prompt',null,

'<table border=\'0\' cellspacing=\'0\'

cellpadding=\'0\'><tr><td width=\'400\'

ClaSS=\'ClPrompt\' align=\'right\'>New York\'s BEST<br>Sightseeing

and<br>Live Music<br>Cruises<td></tr></table>');

window.status='English'; return true"

onMouseOut="window.status-''; return true">

<img src="eng.gi£" alt=""

border="0"></A>finbsp;

<A HREF="javascript:myLink('ger');"

onMouseOver="javascript:layerWrite('prompt',null,

'<table border=\'0\' cellspacing=\'0\' cellpadding=\

' 0\ '><tr><td width=\' 400\ ' class=\'

clPrompt\' align=\' right\' >... <td></tr></table>'.);

window.status='Germanic'; return true"

onMouseOut="window.status='';

return true"><irag src="ger.gif" alt=""

border="0"x/A>&nbsp;

<A HREF="javascript:myLink('spa');"

onMouseOver="javascript:layerWrite('prompt',null,'

<table border=\'0\' cellspacing=\'0\'

cellpadding=\'0\'><tr><td width=\'400\'

class=\'clPrompt\' align=\'right\'>...<td></tr></table>');

window.status='Spanish'; return true"

onMouseOut="window.status='';

return true"><img src="spa.gif" alt=""

border="0"></A> </TDX/TRX/TABLE> </FORM> <MAP name="MyMap">

<AREA alt="Sightseeing Cruises" coords="45,205,188,217"

href="SightseeingCruises.cfm">

<AREA alt="Harbor Lights Evening" coords="45,236,188,248"

href="HarborLightsEvening.cfm">

<AREA alt="Special Events" coords="45,267,188,280"

href="SpecialEvents.cfm"> </map> </CFIF>

</BODY> </HTML>

В коде страницы my_line.cfm присутствуют ссылки на следующие файлы:

<A HREF="javascript:myLink('eng');"

onMouseOver="javascript:layerWrite('prompt',null,

'<table border=\'0\' cellspacing=\'0\' cellpadding=\'0\'><tr><td

width=\'400\' Class=\'clPrompt\' align=\'right\'>New York\'s

BEST<br>Sightseeing and<br>Live Music<br>Cruises<tdx/trX/table>');

window.status='English';

return true"

onMouseOut="window.status='';

return true"><img src="eng.gif" alt=""

border="0"></A>&nbsp;

<A HREF="javascript:myLink('ger');"

onMouseOver="javascript:layerWrite('prompt',null,

'<table border=\'0\' cellspacing=\'0\'

cellpadding=\ ' 0\'><tr><td width=\ '

400\ ' class=\ ' clPrompt\ ' align=\ '

right\ ' >. . . <td></tr></table>'.) ;

window.status='Germanic'; return true"

onMouseOut="window.status='';

return true"><img src="ger.gif" alt=""

border="0"></A>&nbsp;

<A HREF="javascript:myLink('spa') ; "

onMouseOver="javascript:layerWrite('prompt',null,'<table border=\'0\'

cellspacing=\'0\' cellpadding=\ ' 0\'><tr><td width=\ ' 400\ '

class=\'clPrompt\' align=\'right\'>...<td></tr></table>'};

window.status='Spanish';

return true" onMouseOut="window.status='';

return true"><img src="spa.gif" alt=""

border="0"></A> </TD></TR></TABLE> </FORM>

<MAP name="MyMap">

<AREA alt="Sightseeing Cruises" coords="45,205,188,217"

href="SightseeingCruises.cfm">

<AREA alt="Harbor Lights Evening" coords="45,236,188,248"

href="HarborLightsEvening.cfm">

<AREA alt="Special Events" coords="45,267,188,280"

href="SpecialEvents.cfm"> </map> </CFIF>

</BODY> </HTML>

В коде страницы my_line.cfm присутствуют ссылки на следующие файлы:

Отметим, не localhost или 127.0.0.1, как это освещалось в главе 6. Все достаточно просто, обращаться к Web-серверу можно и по его имени. И если ваш сервер называется myweb, то и указывать путь к нему вы можете как http://myweb/my-app/.

Для нашего примера, выбрав на странице один из национальных флагов, предположим флаг Соединенных Штатов, загрузится англоязычная часть страницы myjine.cfm с указанными параметрами . Если флажок То remember the chosen language of viewing (Сохранить выбранный язык для просмотра) будет отмечен, то при следующей загрузке мы сразу окажемся на англоязычной части страницы.

Мы не описываем страницу commercial.cfm с дополнительной информацией в силу простоты кода. Вы можете разработать эту страницу самостоятельно.

Описание кода

Теперь давайте разберем код страницы my_line.cfm без учета классических HTML-тегов и вспомогательных текстов.

Таблица 7.2. Анализ кода страницы myjine.cfm

Код

Описание

<script> function myLink(lang) {

linecommand="window. location. href = 'my line. cfm?language="+

Блок функций.

Функция myLink открывает страницу myjine.cfm с параметрами language И remlang.

Код

Описание

+lang+"sremlang="+

Функция chbRemLang использу-

document . f orml . RemLang . value+" ' " ;

ется для переопределения зна-

eval (linecorttmand) ;

чения элемента RemLang формы


form!. Элемент RemLang имеет

}

тип checkbox (флажок), значе-


ние которого не зависит от со-


стояния флажка. Это связано с

function chbRemLang (value) {

тем, что форму обычно исполь-

if (value=='Yes ' ) {

зуют с параметром action, где

document . f orml . RemLang . value= ' No ' ;

значение флажка передается только в том случае, когда

} else {

флажок отмечен. Нас это не

document . f orml . RemLang . value= ' Yes ' ;

устраивает, т. к. значение этого элемента мы отправляем в ка-

}

честве параметра вручную. Вот

)

и приходится "играть" на собы-


тии onChange. Если элемент

</script>

RemLang принимал значение


Yes, следовательно, в момент


изменения флажка значение


данного элемента должно при-


нять противоположное значение.


И наоборот

<CFIF isDef ined ( "Cookie . language" )

Если существует Cookie.

OR isDefined ("language") >

language ил1/1 страница вклю-


чает параметр language, тогда


в HTML-страницу помещается


код, расположенный ниже


вплоть до раздела <CFELSE>

<CFIF isDefined ('"Cookie . language" ) >

Если существует Cookie.

<CFSET language=#Cookie . language#>

language, определяем пере-


менную language независимо

</CFIF>

от ее существования

<CFIF isDef ined ( "remlang" ) >

Если существует параметр

<CFIF remlang eq "Yes">

remlang, равный Yes (что ука-


зывает на согласие пользовате-

<CFCOOKIE NAME=" language"

ля с необходимостью запомнить

VALUE="#language#"

выбранный язык просмотра), устанавливаем cookie равным

EXPIRES="7">

language на семь дней

</CFIF>


</CFIF>


<CFSWITCH EXPRESSlON=#language#>

Используем тег <CFSWITCH>

<CFCASE VALUE="rus">

условного оператора.

Русский текст . . .

Исходя из значения переменной


language, помещаем необхо-

</CFCASE>

димый текст

<CFCASE VALUE="eng">


Английский текст . . .


</CFCASE>


<CFCASE VALUE="ger">


Немецкий текст . . .


</CFCASE>


<CFCASE VALUE="spa"->


i


Испанский текст . . .


</CFCASE>


<CFDEFAULTCASE>


</CFDEFAULTCASE>


</CFSWITCH>


<CFIF is Defined ( "Cookie . commercial")

Если не существует

is False>

Cookie . commercial, устанав-

<CCFCOOKIE NAME="commercial"

ливаем cookie равным


commercial до 31 декабря

VALUE="1"

2001 года

EXPIRES="12/31/2001">


<CFELSE>

Иначе. Cookie. commercial

<CFIF iCookie. commercial! eq 1>

определен и равен 1.

<script>

Открываем страницу commer-


cial. cfm с дополнительной ин-

Variable = window. open ( "commercial . cfm",

формацией в отдельном окне

"windowname", "top=10, left=530,


width=250, height=490" ) ;


</script>


</CFIF>


</CFIF>


<CFELSE>

Иначе. Cookie . language не определен или отсутствует параметр language, тогда в HTML-страницу помещается код, расположенный ниже вплоть до раздела окончания тега оператора <CFIF>

<FORM method='post ' name= ' forml ' >

<input type="checkbox" name="RemLang" value="Yes" checked onChange = "javascript : chbRemLang (this .value) ; ">

Формируем текст первой страницы с формой выбора национального языка для дальнейшей работы

To remember the chosen language of viewing


<A HREF=" javascript :myLink ( ' rus ' ) ; ">


<img src="rus .gif " alt="" border="0"></A>&nbsp;


<A HREF=" javascript :myLink( ' eng ' ) ; ">


<img src="eng.gif " alt="" border="0"x/A>&nbsp;


<A HREF=" javascript :myLink( 'ger ' ) ; ">

<img src="ger . gif " alt="" border="0"></A>&nbsp;


<A HREF="javascript:myLink( 'spa' } ; ">


<img src="spa. gif " alt="" border="0"></A>


</FORM>


</CFIF>

Конец тега <CFIF> условного оператора

В качестве самостоятельной работы можете попробовать совместить полученные знания о cookies с примером из предыдущего урока, где при каждом открытии страницы welcome_flex.cfm мы принуждали пользователя заполнять данные о себе, что, в общем-то, не всегда разумно, если эти данные можно сохранить у клиента через браузер сразу же при первом запросе. А при очередном открытии страницы считывать однажды введенные значения cookies. При этом еще раз отметим, что пользователь имеет возможность удалять cookies, размещенные у него на компьютере.

Впрочем, здесь вы можете при определении языка просмотра направлять пользователя на другую заранее сформированную страницу, например на index_en.cfm в данном случае с текстом на английском языке.

Существуют и другие способы задания значений cookie, через теги <МЕТА> языка HTML, JavaScript- и CGI-сценарии.

Резюме

Подведем итог. В данной главе мы использовали CFML-теги: <CFCOOKIE>, <CFSWITCH>/<CFCASE>/<CFDEFAULTCASE>.